package org.hfy.collections.helper;

import org.hfy.Constants;

import java.util.LinkedList;
import java.util.List;
import java.util.Set;

/**
 * @Description:
 * @Author: Takagi
 * @date: 2023/4/23
 */
public class SymbolString {
    public List<Symbol> symbolList = new LinkedList<>();

    public List<Symbol> getSymbolList() {
        return symbolList;
    }

    /*
     * @Author Takagi
     * @Description: 获取符号个数
     * @date: 2023/4/26
     * @param
     * @return * @return int
     **/
    public int size() {
        return this.symbolList.size();
    }

    /*
     * @Author Takagi
     * @Description: 获取 item 的位置
     * @date: 2023/4/25
     * @param
     * @return * @return int
     **/
    public int indexOfItem() {
        return this.symbolList.indexOf(new Symbol(Constants.LR0_ITEM));
    }

    /*
     * @Author Takagi
     * @Description: 获取 symbol 在符号串中的下标
     * @date: 2023/5/13
     * @param symbol
     * @return * @return int
     **/
    public int indexOf(Symbol symbol) {
        return this.symbolList.indexOf(symbol);
    }

    /*
     * @Author Takagi
     * @Description: 获取下标 [start, end) 内的符号串
     * @date: 2023/5/13
     * @param start
     * @param end
     * @return * @return SymbolString
     **/
    public SymbolString subString(int start, int end) {
        List<Symbol> symbols = this.symbolList.subList(start, end);
        SymbolString res = new SymbolString();
        res.extendSymbols(symbols);
        return res;
    }

    /*
     * @Author Takagi
     * @Description: 添加一个符号
     * @date: 2023/4/25
     * @param symbol
     * @return
     **/
    public void addSymbol(Symbol symbol) {
        this.symbolList.add(symbol);
    }

    public void addSymbol(String symbol) {
        this.symbolList.add(new Symbol(symbol));
    }

    /*
     * @Author Takagi
     * @Description: 在指定位置添加符号
     * @date: 2023/4/25
     * @param idx
     * @param symbol
     * @return
     **/
    public void addSymbol(int idx, Symbol symbol) {
        this.symbolList.add(idx, symbol);
    }

    public Symbol getNext(Symbol symbol) {
        int idx = this.indexOf(symbol);
        if (idx == -1 || idx == this.size() - 1) return null;
        return this.symbolList.get(idx + 1);
    }

    /*
     * @Author Takagi
     * @Description: 获取符号串的第一个符号
     * @date: 2023/4/25
     * @param
     * @return * @return Symbol
     **/
    public Symbol getFirstSymbol() {
        if (this.symbolList.size() > 0) {
            return this.symbolList.get(0);
        } else {
            return null;
        }
    }

    /*
     * @Author Takagi
     * @Description: 获取符号串的最后一个符号
     * @date: 2023/4/25
     * @param
     * @return * @return Symbol
     **/
    public Symbol getLastSymbol() {
        if (this.symbolList.size() > 0) {
            return this.symbolList.get(this.symbolList.size() - 1);
        } else {
            return null;
        }
    }

    /*
     * @Author Takagi
     * @Description: 获取倒数第二个符号
     * @date: 2023/4/25
     * @param
     * @return * @return Symbol
     **/
    public Symbol getPenultimateSymbol() {
        if (this.symbolList.size() > 1) {
            return this.symbolList.get(this.symbolList.size() - 2);
        } else {
            return null;
        }
    }

    /*
     * @Author Takagi
     * @Description: 获取 LR0 项目的下一个符号
     * @date: 2023/4/25
     * @param
     * @return * @return Symbol
     **/
    public Symbol getItemNextSymbol() {
        for (int i = 0; i < this.symbolList.size(); ++i) {
            if (Constants.isLR0Item(this.symbolList.get(i))) {
                if (i == this.symbolList.size() - 1) {
                    return new Symbol(Constants.EOF);
                } else {
                    return this.symbolList.get(i + 1);
                }
            }
        }
        return null;
    }

    /*
     * @Author Takagi
     * @Description: 扩展另一个符号串的所有符号
     * @date: 2023/4/25
     * @param symbolString
     * @return
     **/
    public void extendSymbols(SymbolString symbolString) {
        this.symbolList.addAll(symbolString.symbolList);
    }

    public void extendSymbols(Set<Symbol> symbolSet) {
        this.symbolList.addAll(symbolSet);
    }

    public void extendSymbols(List<Symbol> symbols) {
        this.symbolList.addAll(symbols);
    }

    public SymbolString(String... symbols) {
        for (String symbol : symbols) {
            this.symbolList.add(new Symbol(symbol));
        }
    }

    @Override
    public String toString() {
        StringBuilder res = new StringBuilder();
        if (Constants.SPLIT_SYMBOL) {
            for (Symbol symbol : this.symbolList) {
                res.append(symbol.toString()).append(Constants.BLANK);
            }
        } else {
            for (Symbol symbol : this.symbolList) {
                res.append(symbol.toString());
            }
        }
        return res.toString();
    }

    @Override
    public boolean equals(Object other) {
        if (other instanceof SymbolString) {
            if (((SymbolString) other).symbolList.size() != this.symbolList.size()) return false;
            for (int i = 0; i < this.symbolList.size(); ++i) {
                if (!((SymbolString) other).symbolList.get(i).equals(this.symbolList.get(i))) {
                    return false;
                }
            }
        }
        return true;
    }

    @Override
    public int hashCode() {
        int code = 0;
        for (Symbol symbol : this.symbolList) {
            code += symbol.hashCode();
        }
        return code;
    }
}
